
#import "WWTCLInterp.h"
#import "WWMovieProcView.h"
#import <ctype.h>

@implementation WWMovieProcView

+ initialize { [WWMovieProcView setVersion:1]; return self; }


- initFrame:(const NXRect *)frameRect
{
   const char  *dragTypes[] = { NXAsciiPboardType, NULL};


   [super initFrame:frameRect];
   [self registerForDraggedTypes:dragTypes count:1];

   tclProcNameSize = 32;
   tclProcName = (char *)NXZoneCalloc([self zone], tclProcNameSize, sizeof(char));
   tclProcArgsSize = 32;
   tclProcArgs = (char *)NXZoneCalloc([self zone], tclProcArgsSize, sizeof(char));
   tclProcBodySize = 32;
   tclProcBody = (char *)NXZoneCalloc([self zone], tclProcBodySize, sizeof(char));
   tclProcTypeSize = 32;
   tclProcType = (char *)NXZoneCalloc([self zone], tclProcTypeSize, sizeof(char));
   // "proc name {args} { body }" is 25; 
   // "proc %s {%s} {%s}" needs a minimum of 11, where the 1st and 3rd %s must be non-NULL
   cmdBuf = (char *)NXZoneCalloc([self zone], (40 + tclProcNameSize + tclProcArgsSize + tclProcBodySize), sizeof(char));
   framed = NO;
   restrictDropToSameName = NO;
   restrictDropToSameType = NO;
   actAsSource = YES;
   actAsSink = YES;
   frameColor = NX_COLORBLACK;
   frameWidth = 3.0;

   // for future stuff...
   nameSwitchView = nil;
   valueSwitchView = nil;
   typeSwitchView = nil;

   return self;
}

- awake
{
   const char  *dragTypes[] = { NXAsciiPboardType, NULL};


   [super awake];
   [self registerForDraggedTypes:dragTypes count:1];

   framed = NO;
   cmdBuf = (char *)NXZoneCalloc([self zone], (40 + tclProcNameSize + tclProcArgsSize + tclProcBodySize), sizeof(char));
   
   return self;
}

- free
{
   const char *fileType[] = { "" };
   Pasteboard *pboard = [Pasteboard newName:NXDragPboard];


   [pboard declareTypes:fileType num:0 owner:nil];
   [self unregisterDraggedTypes];
   image = nil; // don't free the potentially shared image
   if (tclProcName) { free(tclProcName); }
   if (tclProcArgs) { free(tclProcArgs); }
   if (tclProcBody) { free(tclProcBody); }
   if (tclProcType) { free(tclProcType); }
   if (cmdBuf) { NXZoneFree([self zone], cmdBuf); }

   return [super free];
}

- reinitializeStringsFromZone:(NXZone *)zone
{
  tclProcName = (char *)NXZoneCalloc(zone, tclProcNameSize, sizeof(char));
  tclProcArgs = (char *)NXZoneCalloc(zone, tclProcArgsSize, sizeof(char));
  tclProcBody = (char *)NXZoneCalloc(zone, tclProcBodySize, sizeof(char));
  tclProcType = (char *)NXZoneCalloc(zone, tclProcTypeSize, sizeof(char));
  cmdBuf = (char *)NXZoneCalloc([self zone], (40 + tclProcNameSize + tclProcArgsSize + tclProcBodySize), sizeof(char));
  return self;
}

- copyFromZone:(NXZone *)zone
{
  id newCopy = [super copyFromZone:zone];

  [newCopy reinitializeStringsFromZone:zone];
  [newCopy setTclProcName:tclProcName];
  [newCopy setTclProcArgs:tclProcArgs];
  [newCopy setTclProcBody:tclProcBody];
  [newCopy setTclProcType:tclProcType];

  return newCopy;
}

- drawSelf:(const NXRect *)rects :(int)num
{
  [super drawSelf:rects :num];
  if (framed)
  {  NXSetColor(frameColor);
     NXFrameRectWithWidth(&bounds, (NXCoord)frameWidth);
  }
  return self;
}

/*-------------------- methods to be the source of a dragging operation */

- mouseDown:(NXEvent *)theEvent
{
   NXPoint  zero = {0.0, 0.0};
   id       thePboard;
   const char  *dragTypes[] = { NXAsciiPboardType, NULL};
   static char *fooBarBaz = "fooBarBaz";

   if (theEvent->flags & NX_COMMANDMASK)  // show the control panel   
   {  return [super mouseDown:theEvent]; // let our super class bring it up
   }

   if (stationaryBehavior == WW_PLAY_MOUSE_CLICK)
   {  //let our super deal with this first, and then do the drag and drop stuff...
      [super mouseDown:theEvent];
   }

   if (!image && ![imageList count]) // we're pretty darn boring; bail
   { return self; 
   }
   if (!actAsSource) { return self; }

   // Prevent default window ordering (this is a new appkit feature)
   [NXApp preventWindowOrdering];

   //get the Pboard
   thePboard = [Pasteboard newName:NXDragPboard];
   [thePboard declareTypes:dragTypes num:1 owner:nil];

   // we're not really going to use this info, we're just sticking something on the board...
   [thePboard writeType:NXAsciiPboardType data:fooBarBaz length:(1 + strlen(fooBarBaz))];
    
   //start the drag
   // if we've no image, use the movieImage
   if (!image)
   {  [self dragImage:movieImage // visible on screen during drag
                   at:&zero	 // offset the mouse point for the drag
               offset:&zero	 // offset the inital mouse pt
                event:theEvent	 // theEvent structure
           pasteboard:thePboard	 // a Pasteboard with data on it
               source:self	 // source object
            slideBack:YES];	 // if no destination animate back to source
   }
   else
   {  [self dragImage:image	// visible on screen during drag
                   at:&zero	// offset the mouse point for the drag
               offset:&zero	// offset the inital mouse pt
                event:theEvent	// theEvent structure
           pasteboard:thePboard	// a Pasteboard with data on it
               source:self		// source object
            slideBack:YES];	// if no destination animate back to source
   }
	
    return self;
}

- draggedImage:(NXImage *)image beganAt:(NXPoint *)screenPoint  { return self; }

- (NXDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag  { return (NX_DragOperationCopy | NX_DragOperationGeneric); }

- draggedImage:(NXImage *)image endedAt:(NXPoint *)screenPoint deposited:(BOOL)flag { return self; }

/*-------------------- methods to be the destination of a dragging operation */

- (NXDragOperation)draggingEntered:sender
{
   if (!actAsSink)
   {  if (framed)
      {  framed = NO;
	 [self display];
      }
      return NX_DragOperationNone;
   }

   // check to make sure we are not the source and this operation is a copy
   if (   ([sender draggingSourceOperationMask] & NX_DragOperationCopy) 
       && ([sender draggingSource] != self)
       && ([[sender draggingSource] respondsTo:@selector(tclProcBody)]))
   {  
      // if we're selective, need to check the var's name
      // if it's not the same as ours, we're outta here
      if (restrictDropToSameName)
      {  if (tclProcName && [[sender draggingSource] tclProcName] && strcmp(tclProcName, [[sender draggingSource] tclProcName]))
         {  if (framed)
	    {  framed = NO;
	       [self display];
 	    }
            return NX_DragOperationNone;
	 }
      }
      if (restrictDropToSameType)
      {  if (tclProcType && [[sender draggingSource] tclProcType] && strcmp(tclProcType, [[sender draggingSource] tclProcType]))
         {  if (framed)
	    {  framed = NO;
	       [self display];
 	    }
            return NX_DragOperationNone;
	 }
      }
      framed = YES;
      [self display];
      //return the type of operation we want to do, this will dictate
      //the type of cursor will show up when accepting the drag
      return NX_DragOperationCopy;
   }
   if (framed) 
   {  framed = NO;
      [self display];
   }
   return NX_DragOperationNone;
}

- (NXDragOperation)draggingUpdated:sender
{
   if (!actAsSink)
   {  if (framed)
      {  framed = NO;
	 [self display];
      }
      return NX_DragOperationNone;
   }

   // make sure that this is a copy operation, and that this instance
   // of DragView is not the source
   if (   ([sender draggingSourceOperationMask] & NX_DragOperationCopy) 
       && ([sender draggingSource] != self)
       && ([[sender draggingSource] respondsTo:@selector(tclProcBody)]))
    { 
      if (restrictDropToSameName)
      {  if (tclProcName && [[sender draggingSource] tclProcName] && strcmp(tclProcName, [[sender draggingSource] tclProcName]))
         {  if (framed)
	    {  framed = NO;
	       [self display];
 	    }
            return NX_DragOperationNone;
	 }
      }
      if (restrictDropToSameType)
      {  if (tclProcType && [[sender draggingSource] tclProcType] && strcmp(tclProcType, [[sender draggingSource] tclProcType]))
         {  if (framed)
	    {  framed = NO;
	       [self display];
 	    }
            return NX_DragOperationNone;
	 }
      }
      framed = YES;
      [self display];
      return NX_DragOperationCopy;
   }
   if (framed) 
   {  framed = NO;
      [self display];
   }
   return NX_DragOperationNone;
}

- draggingExited:sender
{
   if (!actAsSink)
   {  if (framed)
      {  framed = NO;
	 [self display];
      }
      return NX_DragOperationNone;
   }

   if (framed) 
   {  framed = NO;
      [self display];
   }
   return self;
}

- (BOOL)prepareForDragOperation:sender  
{  
   if (!actAsSink)
   {  if (framed)
      {  framed = NO;
	 [self display];
      }
      return NO;
   }
   return YES; 
}

static int notJustBlanks(const char *str)
{
  const char  *ptr;


  ptr = str;
  if (ptr)
  {  while (*ptr && isspace(*ptr))
     {  ptr++;
     }
     if (*ptr) // if we're not at the end and we stopped, it's not just blanks...
     {  return 1;
     }
  }
  return 0;
}


- (BOOL)performDragOperation:sender
{
   if (!actAsSink)
   {  if (framed)
      {  framed = NO;
	 [self display];
      }
      return NO;
   }

   // make sure that what we are getting is from the same application
   // and did not originate from this view.
   if (   [sender isDraggingSourceLocal] 
       && ([sender draggingSource] != self) 
       && ([[sender draggingSource] respondsTo:@selector(tclProcBody)]))

   {  // should check to make sure the sender will respond appropriately...
      if (restrictDropToSameName)
      {  if (tclProcName && [[sender draggingSource] tclProcName] && strcmp(tclProcName, [[sender draggingSource] tclProcName]))
         {  if (framed) 
	    {  framed = NO;
	       [self display];
	    }
	    return NO;
	 }
      }
      if (restrictDropToSameType)
      {  if (tclProcType && [[sender draggingSource] tclProcType] && strcmp(tclProcType, [[sender draggingSource] tclProcType]))
         {  if (framed) 
            {  framed = NO;
	       [self display];
	    }
	    return NO;
	 }
      }
      [self setImage:nil];
      if ([[sender draggingSource] image])
      {  [self setImage:[[sender draggingSource] image]];
      }
      else
      {  [self setImage:[[sender draggingSource] movieImage]];
      }
      [self setTclProcArgs:[[sender draggingSource] tclProcArgs]];
      [self setTclProcBody:[[sender draggingSource] tclProcBody]];
      if (nameSwitchView)
      {  //[nameSwitchView showViewNamed:tclProcName];
      }
      if (typeSwitchView)
      {  //[typeSwitchView showViewNamed:tclProcType];
      }
      if (notJustBlanks(tclProcBody))
      {  // cmdBuf is basically "proc <tclProcName> {<tclProcArgs>} {<tclProcBody>}"
         if (notJustBlanks(tclProcArgs))
         {  sprintf(cmdBuf, "proc %s {%s} {%s}", tclProcName, tclProcArgs, tclProcBody);
            [interp globalEval:cmdBuf];
 	 }
         else
         {  sprintf(cmdBuf, "proc %s {} {%s}", tclProcName, tclProcBody);
            [interp globalEval:cmdBuf];
 	 }
      }
      framed = NO;
      [self display];
   }
   if (framed) 
   {  framed = NO;
      [self display];
   }
   return YES;
}

- concludeDragOperation:sender {  return self; }

/*-------------------- methods to display, and other useful stuff */

- (BOOL)acceptsFirstMouse  {  return YES; }

- (BOOL)shouldDelayWindowOrderingForEvent:(NXEvent *)theEvent {  return YES; }

// set and get stuff

- setTclProcArgs:(const char *)str 
{ 
  int   cnt;


  if (tclProcArgsSize <= 0) 
  {  tclProcArgsSize = 32; 
     tclProcArgs = (char *)NXZoneCalloc([self zone], tclProcArgsSize, sizeof(char));
     cmdBuf = (char *)NXZoneCalloc([self zone], (40 + tclProcNameSize + tclProcArgsSize + tclProcBodySize), sizeof(char));
  }
  cnt = strlen(str);
  while (cnt >= tclProcArgsSize)
  {  tclProcArgsSize *= 2;
     tclProcArgs = (char *)NXZoneRealloc([self zone], tclProcArgs, tclProcArgsSize);
  }
  cmdBuf = (char *)NXZoneCalloc([self zone], (40 + tclProcNameSize + tclProcArgsSize + tclProcBodySize), sizeof(char));
  strcpy(tclProcArgs, str); 
  return self; 
}
//
- (const char *)tclProcArgs { return tclProcArgs; }


- setTclProcBody:(const char *)str 
{ 
  int   cnt;


  if (tclProcBodySize <= 0) 
  {  tclProcBodySize = 32; 
     tclProcBody = (char *)NXZoneCalloc([self zone], tclProcBodySize, sizeof(char));
     cmdBuf = (char *)NXZoneCalloc([self zone], (40 + tclProcNameSize + tclProcArgsSize + tclProcBodySize), sizeof(char));
  }
  cnt = strlen(str);
  while (cnt >= tclProcBodySize)
  {  tclProcBodySize *= 2;
     tclProcBody = (char *)NXZoneRealloc([self zone], tclProcBody, tclProcBodySize);
  }
  cmdBuf = (char *)NXZoneCalloc([self zone], (40 + tclProcNameSize + tclProcArgsSize + tclProcBodySize), sizeof(char));
  strcpy(tclProcBody, str); 
  return self; 
}
//
- (const char *)tclProcBody { return tclProcBody; }


- setTclProcName:(const char *)str 
{ 
  int   cnt;


  if (tclProcNameSize <= 0) 
  {  tclProcNameSize = 32; 
     tclProcName = (char *)NXZoneCalloc([self zone], tclProcNameSize, sizeof(char));
     cmdBuf = (char *)NXZoneCalloc([self zone], (40 + tclProcNameSize + tclProcArgsSize + tclProcBodySize), sizeof(char));
  }
  cnt = strlen(str);
  while (cnt >= tclProcNameSize)
  {  tclProcNameSize *= 2;
     tclProcName = (char *)NXZoneRealloc([self zone], tclProcName, tclProcNameSize);
  }
  cmdBuf = (char *)NXZoneCalloc([self zone], (40 + tclProcNameSize + tclProcArgsSize + tclProcBodySize), sizeof(char));
  strcpy(tclProcName, str); 
  return self; 
}
//
- (const char *)tclProcName { return tclProcName; }

- setTclProcType:(const char *)str 
{ 
  int   cnt;


  if (tclProcTypeSize <= 0) 
  {  tclProcTypeSize = 32; 
     tclProcType = (char *)NXZoneCalloc([self zone], tclProcTypeSize, sizeof(char));
  }
  cnt = strlen(str);
  while (cnt >= tclProcTypeSize)
  {  tclProcTypeSize *= 2;
     tclProcType = (char *)NXZoneRealloc([self zone], tclProcType, tclProcTypeSize);
  }
  strcpy(tclProcType, str); 
  return self; 
}
//
- (const char *)tclProcType { return tclProcType; }


- (BOOL)restrictDropToSameName { return restrictDropToSameName; }
- setRestrictDropToSameName:(BOOL)flag {  restrictDropToSameName = flag; return self; }

- (BOOL)restrictDropToSameType { return restrictDropToSameType; }
- setRestrictDropToSameType:(BOOL)flag {  restrictDropToSameType = flag; return self; }

- (BOOL)actAsSink { return actAsSink; }
- setActAsSink:(BOOL)flag 
{  if (actAsSink && !flag) // we're about to turn it off...
   {  [self unregisterDraggedTypes];
   }
   if (!actAsSink && flag) // we're about to turn it on...
   {  const char  *dragTypes[] = { NXAsciiPboardType, NULL};
      [self registerForDraggedTypes:dragTypes count:1];
   }
   
   actAsSink = flag; 
   return self; 
}

- (BOOL)actAsSource { return actAsSource; }
- setActAsSource:(BOOL)flag {  actAsSource = flag; return self; }

// IB stuff
- (const char *)getInspectorClassName 
{  
   NXEvent  *event = [NXApp currentEvent];

   if (event->flags & NX_ALTERNATEMASK)
   {  return [super getInspectorClassName];
   }
   
   return "WWMovieProcViewIBInspector"; 
}

- write:(NXTypedStream *)stream 
{
   [super write:stream];
   NXWriteTypes(stream, "****cccfc", &tclProcName, &tclProcArgs, &tclProcBody, &tclProcType, 
		&restrictDropToSameName, &restrictDropToSameType, &actAsSource, &frameWidth, &actAsSink);
   NXWriteColor(stream, frameColor);
   return self;
}
//
- read:(NXTypedStream *)stream 
{
   int version;

   [super read:stream];

   version = NXTypedStreamClassVersion(stream, "WWMovieProcView");
   if (version == 1)
   {  NXReadTypes(stream, "****cccfc", &tclProcName, &tclProcArgs, &tclProcBody, &tclProcType, 
		   &restrictDropToSameName, &restrictDropToSameType, &actAsSource, &frameWidth, &actAsSink);
      frameColor = NXReadColor(stream);
      if (tclProcName)
      {  tclProcNameSize = strlen(tclProcName) + 1;
      }
      else
      {  tclProcNameSize = 0;
      }

      if (tclProcArgs)
      {  tclProcArgsSize = strlen(tclProcArgs) + 1;
      }
      else
      {  tclProcArgsSize = 0;
      }

      if (tclProcBody)
      {  tclProcBodySize = strlen(tclProcBody) + 1;
      }
      else
      {  tclProcBodySize = 0;
      }

      if (tclProcType)
      {  tclProcTypeSize = strlen(tclProcType) + 1;
      }
      else
      {  tclProcTypeSize = 0;
      }
   }
   return self;
}



@end
